/**
 * 玩家服务类
 * 封装玩家相关的业务逻辑
 */
import { Player } from '../entity/Player';
import { PlayerDAO } from '../dao/PlayerDAO';

export class PlayerService {
  // 单例实例
  private static instance: PlayerService | null = null;
  
  /**
   * 私有构造函数
   */
  private constructor() {}
  
  /**
   * 获取玩家服务实例
   * @returns 玩家服务实例
   */
  public static getInstance(): PlayerService {
    if (!PlayerService.instance) {
      PlayerService.instance = new PlayerService();
    }
    return PlayerService.instance;
  }
  
  /**
   * 创建新玩家
   * @param name 玩家名称
   * @param avatar 玩家头像（可选）
   * @returns 创建的玩家
   */
  public async createPlayer(name: string, avatar: string = '🎭'): Promise<Player> {
    try {
      // 验证输入数据
      if (!name || name.trim().length === 0) {
        throw new Error('玩家名称不能为空');
      }
      
      if (name.length > 20) {
        throw new Error('玩家名称不能超过20个字符');
      }
      
      // 创建玩家对象
      const newPlayer = new Player({
        name: name.trim(),
        avatar: avatar,
        roleType: 'amateur'
      });
      
      // 保存到数据库
      return await PlayerDAO.createPlayer(newPlayer);
    } catch (error) {
      console.error('创建玩家失败:', error);
      throw error;
    }
  }
  
  /**
   * 获取所有玩家
   * @returns 所有玩家列表
   */
  public async getAllPlayers(): Promise<Player[]> {
    try {
      return await PlayerDAO.getAllPlayers();
    } catch (error) {
      console.error('获取所有玩家失败:', error);
      throw error;
    }
  }
  
  /**
   * 根据ID获取玩家
   * @param playerId 玩家ID
   * @returns 玩家对象或null
   */
  public async getPlayerById(playerId: string): Promise<Player | null> {
    try {
      if (!playerId) {
        throw new Error('玩家ID不能为空');
      }
      
      return await PlayerDAO.getPlayerById(playerId);
    } catch (error) {
      console.error('根据ID获取玩家失败:', error);
      throw error;
    }
  }
  
  /**
   * 更新玩家信息
   * @param player 玩家对象
   * @returns 更新后的玩家对象
   */
  public async updatePlayer(player: Player): Promise<Player> {
    try {
      if (!player || !player.id) {
        throw new Error('玩家对象或ID不能为空');
      }
      
      // 更新最后在线时间
      player.updateLastOnline();
      
      return await PlayerDAO.updatePlayer(player);
    } catch (error) {
      console.error('更新玩家信息失败:', error);
      throw error;
    }
  }
  
  /**
   * 获取玩家信息（兼容旧方法）
   * @param playerId 玩家ID
   * @returns 玩家信息
   */
  public async getPlayerInfo(playerId: string): Promise<Player | null> {
    return await this.getPlayerById(playerId);
  }
  
  /**
   * 更新玩家信息（兼容旧方法）
   * @param playerId 玩家ID
   * @param updates 更新内容
   * @returns 更新后的玩家
   */
  public async updatePlayerInfo(playerId: string, updates: Partial<{
    name: string;
    avatar: string;
    currentCaseId: string;
  }>): Promise<Player | null> {
    try {
      // 获取玩家
      const player = await this.getPlayerById(playerId);
      if (!player) {
        throw new Error(`玩家不存在: ${playerId}`);
      }
      
      // 应用更新
      if (updates.name !== undefined) {
        if (updates.name.trim().length === 0) {
          throw new Error('玩家名称不能为空');
        }
        if (updates.name.length > 20) {
          throw new Error('玩家名称不能超过20个字符');
        }
        player.name = updates.name.trim();
      }
      
      if (updates.avatar !== undefined) {
        player.avatar = updates.avatar;
      }
      
      if (updates.currentCaseId !== undefined) {
        player.currentCaseId = updates.currentCaseId;
      }
      
      // 保存更新
      return await this.updatePlayer(player);
    } catch (error) {
      console.error('更新玩家信息失败:', error);
      throw error;
    }
  }
  
  /**
   * 增加玩家经验值
   * @param playerId 玩家ID
   * @param amount 经验值数量
   * @returns 是否升级
   */
  public async addPlayerExperience(playerId: string, amount: number): Promise<boolean> {
    try {
      if (!playerId) {
        throw new Error('玩家ID不能为空');
      }
      
      const player = await this.getPlayerById(playerId);
      if (!player) {
        throw new Error(`玩家不存在: ${playerId}`);
      }
      
      // 确保经验值为正数
      if (amount <= 0) {
        throw new Error('经验值必须为正数');
      }
      
      // 添加经验值
      const didLevelUp = player.addExperience(amount);
      
      // 如果升级，更新角色类型
      if (didLevelUp) {
        this.updatePlayerRoleType(player);
      }
      
      // 保存更新
      await this.updatePlayer(player);
      
      return didLevelUp;
    } catch (error) {
      console.error('增加玩家经验值失败:', error);
      throw error;
    }
  }
  
  /**
   * 玩家获得积分
   * @param playerId 玩家ID
   * @param amount 积分数量
   */
  public async gainPoints(playerId: string, amount: number): Promise<void> {
    try {
      const player = await PlayerDAO.getPlayerById(playerId);
      if (!player) {
        throw new Error(`玩家不存在: ${playerId}`);
      }
      
      // 确保积分为正数
      if (amount <= 0) {
        throw new Error('积分必须为正数');
      }
      
      // 添加积分
      player.addPoints(amount);
      
      // 更新最后在线时间
      player.updateLastOnline();
      
      // 保存更新
      await PlayerDAO.updatePlayer(player);
    } catch (error) {
      console.error('玩家获得积分失败:', error);
      throw error;
    }
  }
  
  /**
   * 收集线索
   * @param playerId 玩家ID
   * @param clueId 线索ID
   * @returns 是否成功收集
   */
  public async collectClue(playerId: string, clueId: string): Promise<boolean> {
    try {
      if (!playerId || !clueId) {
        throw new Error('玩家ID或线索ID不能为空');
      }
      
      const player = await this.getPlayerById(playerId);
      if (!player) {
        throw new Error(`玩家不存在: ${playerId}`);
      }
      
      // 收集线索
      const success = player.collectClue(clueId);
      
      if (success) {
        // 给予收集线索的奖励
        player.addPoints(5); // 收集线索获得5积分
        player.addExperience(10); // 收集线索获得10经验
        
        // 更新角色类型（如果经验足够升级）
        this.updatePlayerRoleType(player);
      }
      
      // 保存更新
      await this.updatePlayer(player);
      
      return success;
    } catch (error) {
      console.error('收集线索失败:', error);
      throw error;
    }
  }
  
  /**
   * 玩家发现证据
   * @param playerId 玩家ID
   * @param evidenceId 证据ID
   * @returns 是否成功发现
   */
  public async discoverEvidence(playerId: string, evidenceId: string): Promise<boolean> {
    try {
      const player = await PlayerDAO.getPlayerById(playerId);
      if (!player) {
        throw new Error(`玩家不存在: ${playerId}`);
      }
      
      // 发现证据
      const success = player.discoverEvidence(evidenceId);
      
      if (success) {
        // 给予发现证据的奖励
        player.addPoints(10); // 发现证据获得10积分
        player.addExperience(20); // 发现证据获得20经验
        
        // 更新角色类型（如果经验足够升级）
        this.updatePlayerRoleType(player);
      }
      
      // 更新最后在线时间
      player.updateLastOnline();
      
      // 保存更新
      await PlayerDAO.updatePlayer(player);
      
      return success;
    } catch (error) {
      console.error('玩家发现证据失败:', error);
      throw error;
    }
  }
  
  /**
   * 完成案件并获得奖励
   * @param playerId 玩家ID
   * @param caseId 案件ID
   * @param score 获得的分数（可选）
   */
  public async completeCase(playerId: string, caseId: string, score: number = 0): Promise<void> {
    try {
      const player = await PlayerDAO.getPlayerById(playerId);
      if (!player) {
        throw new Error(`玩家不存在: ${playerId}`);
      }
      
      // 增加已解决案件数
      player.solvedCases++;
      
      // 添加案件到已解决列表
      if (!player.casesSolved) {
        player.casesSolved = [];
      }
      if (!player.casesSolved.includes(caseId)) {
        player.casesSolved.push(caseId);
      }
      
      // 给予完成案件的奖励
      let pointsReward = 100;
      let expReward = 200;
      
      // 如果提供了分数，使用分数作为基础奖励
      if (score > 0) {
        pointsReward = score;
        expReward = Math.floor(score * 2);
      } else {
        // 否则使用等级相关的奖励
        const levelMultiplier = player.level * 0.1; // 每级增加10%
        pointsReward = Math.floor(pointsReward * (1 + levelMultiplier));
        expReward = Math.floor(expReward * (1 + levelMultiplier));
      }
      
      player.addPoints(pointsReward);
      player.addExperience(expReward);
      
      console.log(`玩家 ${player.name} 完成案件 ${caseId}，获得 ${pointsReward} 积分和 ${expReward} 经验`);
      
      // 更新角色类型（如果经验足够升级）
      this.updatePlayerRoleType(player);
      
      // 更新最后在线时间
      player.updateLastOnline();
      
      // 保存更新
      await PlayerDAO.updatePlayer(player);
      
      console.log(`玩家 ${player.name} 完成案件 ${caseId}，获得 ${pointsReward} 积分和 ${expReward} 经验`);
    } catch (error) {
      console.error('玩家完成案件失败:', error);
      throw error;
    }
  }
  
  /**
   * 更新玩家角色类型
   * @param player 玩家对象
   */
  private updatePlayerRoleType(player: Player): void {
    // 根据等级更新角色类型
    if (player.level >= 20) {
      player.roleType = 'genius';
    } else if (player.level >= 10) {
      player.roleType = 'master';
    } else if (player.level >= 5) {
      player.roleType = 'detective';
    } else {
      player.roleType = 'amateur';
    }
  }
  
  /**
   * 获取玩家排行榜
   * @param limit 返回数量限制
   * @returns 玩家排行榜
   */
  public async getPlayerRanking(limit: number = 10): Promise<Player[]> {
    try {
      return await PlayerDAO.getPlayerRanking(limit);
    } catch (error) {
      console.error('获取玩家排行榜失败:', error);
      return [];
    }
  }
  
  /**
   * 获取在线玩家列表
   * @returns 在线玩家列表
   */
  public async getOnlinePlayers(): Promise<Player[]> {
    try {
      return await PlayerDAO.getOnlinePlayers();
    } catch (error) {
      console.error('获取在线玩家失败:', error);
      return [];
    }
  }
  
  /**
   * 获取玩家统计信息
   * @returns 玩家统计信息
   */
  public async getPlayerStatistics(): Promise<{
    totalPlayers: number;
    onlinePlayers: number;
    topPlayer: Player | null;
    averageLevel: number;
  }> {
    try {
      const allPlayers = await PlayerDAO.getAllPlayers();
      const onlinePlayers = await PlayerDAO.getOnlinePlayers();
      const rankings = await PlayerDAO.getPlayerRanking(1);
      
      const totalExperience = allPlayers.reduce((sum, player) => sum + player.experience, 0);
      const averageLevel = allPlayers.length > 0 
        ? Number((totalExperience / allPlayers.length).toFixed(1))
        : 0;
      
      return {
        totalPlayers: allPlayers.length,
        onlinePlayers: onlinePlayers.length,
        topPlayer: rankings.length > 0 ? rankings[0] : null,
        averageLevel
      };
    } catch (error) {
      console.error('获取玩家统计信息失败:', error);
      return {
        totalPlayers: 0,
        onlinePlayers: 0,
        topPlayer: null,
        averageLevel: 0
      };
    }
  }
}